/**
 * @file src/Main.java
 */

/** imports */
import datatypes.Heuristics;
import datatypes.Map3D;
import datatypes.Path;
import datatypes.Point3D;
// import datatypes.ScheduleLinear;
import datatypes.ScheduleQuadratic;
import datatypes.UndirectedGraph;
import java.util.Scanner;
import java.util.Vector;
import search.AStar;
import search.LocalBeam;
import search.SimulatedAnnealing;

/**
 * Main class 
 */
public class Main
{
	/**
	 *  ASTAR = 0
	 *  BEAMHILL = 1
	 *  SIMHILL = 2 
	 */
	private static final int algo = 2;

	/** set to true, if input should be filled automatically */
	private static final boolean autofill = true;

	/**
	 * Main
	 * 
	 * @param args
	 */
	public static void main(String[] args)
	{
		/** switch algo */
		switch (algo) {
			case 0: { astar(autofill); break; }
			case 1: { beamhill(autofill); break; }
			case 2: { simhill(autofill); break; }
			default: { astar(autofill); }
		}
        
    } // main(String[] args)

	
	/**
	 * Call AStar
	 */
	public static void astar(Boolean... autoFill)
	{
		System.out.println("ASTAR");
		System.out.println();
		
		/** defaults to false */
	    boolean isAutoFill = autoFill.length > 0 ? autoFill[0].booleanValue() : false; 

		/** variables for input */
		String graphFile;
		String heurFile;
		String source;
		String goal;
		
		if (isAutoFill) {
			int choose = 5;
			
			switch (choose) {
				case 1 :
				{
					graphFile = "../../../assignment/tutorial2/tutorial2-2008-PART1-Graph1-graph_info.txt";
					System.out.println("File location of graph: " + graphFile);
					heurFile = "../../../assignment/tutorial2/tutorial2-2008-PART1-Graph1-heuristic-distance.txt";
					System.out.println("File location of heuristics: " + heurFile);
					source = "A";
					System.out.println("Source state: " + source);
					goal = "G";
					System.out.println("Goal state: " + goal);
					break;
				}
				case 2 :
				{
					graphFile = "../../../assignment/tutorial2/tutorial2-2008-PART1-Graph2-graph_info.txt";
					System.out.println("File location of graph: " + graphFile);
					heurFile = "../../../assignment/tutorial2/tutorial2-2008-PART1-Graph2-heuristic-distance.txt";
					System.out.println("File location of heuristics: " + heurFile);
					source = "A";
					System.out.println("Source state: " + source);
					goal = "G";
					System.out.println("Goal state: " + goal);
					break;
				}
				case 3 :
				{
					graphFile = "../../../assignment/tutorial2/tutorial2-2008-PART1-Graph3-graph_info.txt";
					System.out.println("File location of graph: " + graphFile);
					heurFile = "../../../assignment/tutorial2/tutorial2-2008-PART1-Graph3-heuristic-distance.txt";
					System.out.println("File location of heuristics: " + heurFile);
					source = "A";
					System.out.println("Source state: " + source);
					goal = "G";
					System.out.println("Goal state: " + goal);
					break;
				}
				case 4 :
				{
					graphFile = "../../../assignment/2011/graph_info-new1.txt";
					System.out.println("File location of graph: " + graphFile);
					heurFile = "../../../assignment/2011/heuristic-distance-new1.txt";
					System.out.println("File location of heuristics: " + heurFile);
					source = "S";
					System.out.println("Source state: " + source);
					goal = "G";
					System.out.println("Goal state: " + goal);
					break;
				}
				case 5 :
				{
					graphFile = "../../../assignment/2011/graph_info-new2.txt";
					System.out.println("File location of graph: " + graphFile);
					heurFile = "../../../assignment/2011/heuristic-distance-new2.txt";
					System.out.println("File location of heuristics: " + heurFile);
					source = "S";
					System.out.println("Source state: " + source);
					goal = "G";
					System.out.println("Goal state: " + goal);
					break;
				}
				default :
				{
					graphFile = "../../../assignment/Romania/romania-graph_info.txt";
					System.out.println("File location of graph: " + graphFile);
					heurFile = "../../../assignment/Romania/romania-heuristic-distance.txt";
					System.out.println("File location of heuristics: " + heurFile);
					source = "Arad";
					System.out.println("Source state: " + source);
					goal = "Bucharest";
					System.out.println("Goal state: " + goal);
					break;
				}
				
			}
				
		} else {
			/** prompt for input */
			
			/** generate Scanner for reading input */
			Scanner sc = new Scanner(System.in);
	
			/** read graphFile */
			System.out.println("File location of graph: ");
			graphFile = sc.nextLine();
			
			/** read heuristics */
			System.out.println("File location of heuristics: ");
			heurFile = sc.nextLine();
			
			/** read source */
			System.out.println("Source state: ");
			source = sc.nextLine();
			
			/** read goal */
			System.out.println("Goal state: ");
			goal = sc.nextLine();
	
			/** close scanner */
			sc.close();            
		}
		System.out.println();
		
		/** generate empty graph and empty heuristics */
		UndirectedGraph graph = new UndirectedGraph();
		Heuristics heur = new Heuristics();		
		
		/** read files and call AStar algorithm */
		try {
			/** read problem */
			graph.read(graphFile);
			heur.read(heurFile);
			
			/** search by AStar */
			Vector<Path> solution = AStar.search(graph, heur, source, goal);
			
			/** print solution */
			System.out.println("Found solution: ");
			if (solution.size() > 0) {
				Path sol = solution.get(0);
				System.out.print("Costs = " + sol.getCosts() + ", ");
				System.out.println(sol.toString());
			}
			System.out.println();
			/** print partial parts */
			System.out.println("Partial paths: ");
						
			for (int i = 1; i < solution.size(); ++i) {
				Path current = solution.get(i);
				System.out.print("F = " + current.getF() + ", ");
				System.out.println(current.toString());
			}
		
		} catch (Exception e) {
			System.out.println(e.toString());
		}
		
	} // astar()
	
	/**
	 * Call beam hill
	 */
	public static void beamhill(Boolean... autoFill)
	{
		System.out.println("LOCAL BEAM HILL CLIMBING");
		System.out.println();
		
		/** for default parameter */
		boolean isAutoFill = autoFill.length > 0 ? autoFill[0].booleanValue() : false; 

		/** variables for input */
		String mapFile;
		
		/** k parameter */
		int k = 4;
		
		if (isAutoFill) {
			int choose = 1;
			
			switch (choose) {
				case 1 :
				{
					mapFile = "../../../assignment/2010/test-map1.txt";
					break;
				}
				default :
				{
					mapFile = "../../../assignment/MyTests/my-test-map-1.txt";
					break;
				}
				
			}
				
		} else {
			/** prompt for input */
			
			/** generate Scanner for reading input */
			Scanner sc = new Scanner(System.in);
	
			/** read graphFile */
			System.out.println("File location of Map: ");
			mapFile = sc.nextLine();
			
			/** read parameter k */
			System.out.println("Number of states to observe k: ");
			k = sc.nextInt();
			
			/** close scanner */
			sc.close();            
		}
		
		System.out.println("File location of Map: " + mapFile);
		System.out.println("Number of states to observe k: " + k);
		System.out.println();
			
		/** generate empty map */
		Map3D map = new Map3D();
	
		/** read files and call local beam search algorithm */
		try {
			/** read problem */
			map.read(mapFile);
		} catch (Exception e) {
			System.out.println(e.toString());
			return;
		}

		/** search by LocalBeam */
		Vector<Point3D> sequence = new Vector<Point3D>();
		Point3D result = null;
		try {
			result = LocalBeam.localBeamHillClimb(map, sequence, k);
		} catch (Exception e) {
			System.out.println(e.toString());
		}
			
		/** print results */
		handleResultsLocalSearch(result, sequence, mapFile);
		
	} // beamhill()


	/**
	 * Call sim hill
	 */
	public static void simhill(Boolean... autoFill)
	{
		System.out.println("SIMULATED ANNEALING HILL CLIMBING");
		System.out.println();
		
		/** for default parameter */
		boolean isAutoFill = autoFill.length > 0 ? autoFill[0].booleanValue() : false; 

		/** variables for input */
		String mapFile;
		int timeBudget = 20;
		
		if (isAutoFill) {
			int choose = 1;
			
			switch (choose) {
				case 1 :
				{
					mapFile = "../../../assignment/2010/test-map1.txt";
					break;
				}
				default :
				{
					mapFile = "../../../assignment/MyTests/my-test-map-1.txt";
					break;
				}
				
			}
				
		} else {
			/** prompt for input */
			
			/** generate Scanner for reading input */
			Scanner sc = new Scanner(System.in);
	
			/** read graphFile */
			System.out.println("File location of Map: ");
			mapFile = sc.nextLine();
			
			/** read parameter k */
			System.out.println("Time budget for scheduler [ms]: ");
			timeBudget = sc.nextInt();
			
			/** close scanner */
			sc.close();            
		}
		System.out.println();
			
		/** generate empty map */
		Map3D map = new Map3D();
	
		/** read files and call local beam search algorithm */
		try {
			/** read problem */
			map.read(mapFile);
		} catch (Exception e) {
			System.out.println(e.toString());
			return;
		}

		/** search by simulated annealing */
		Vector<Point3D> sequence = new Vector<Point3D>();
		Point3D result = null;
		
		/** Scheduler */
		// ScheduleLinear schedule = new ScheduleLinear(10000);
		ScheduleQuadratic schedule = new ScheduleQuadratic(timeBudget); 
		
		try {
			result = SimulatedAnnealing.simAnnealHillClimb(map, sequence, schedule);
		} catch (Exception e) {
			System.out.println(e.toString());
		}
			
		/** print results */
		handleResultsLocalSearch(result, sequence, mapFile);

		
	} // beamhill()

	
	private static void handleResultsLocalSearch(Point3D result, Vector<Point3D> sequence, String mapFile)
	{
		/** print out solution */
		System.out.println("Found point with highest peak: " + result.toString());

		/** write sequence to file */
		String seqFile = mapFile.substring(0, mapFile.length() - 4);
		seqFile += "-Sequence.txt";
		
		try {
			System.out.println();
			final int maxWritable = 3000;
			if (sequence.size() > maxWritable) {
				System.out.println("Warning: sequence file very big. Can take awhile");
			}
			String sequenceString = Map3D.writeSequenceToFile(seqFile, sequence);
			System.out.println("Sequence written to " + seqFile + ": ");
			
			final int maxPrintable = 500;
			if (sequence.size() < maxPrintable) {
				System.out.println(sequenceString);
			} else {
				System.out.println("No output, sequence > " + maxPrintable);
			}
		} catch (Exception e) {
			System.out.println(e.toString());
		}
		
	} // handleResultsLocalSearch(Vector<Point3D> results, String mapFile)
	
	
} // class Main
